/* Copyright Statement:
*
* This software/firmware and related documentation ("MediaTek Software") are
* protected under relevant copyright laws. The information contained herein
* is confidential and proprietary to MediaTek Inc. and/or its licensors.
* Without the prior written permission of MediaTek inc. and/or its licensors,
* any reproduction, modification, use or disclosure of MediaTek Software,
* and information contained herein, in whole or in part, shall be strictly prohibited.
*/
/* MediaTek Inc. (C) 2010. All rights reserved.
*
* BY OPENING THIS FILE, RECEIVER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND AGREES
* THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK SOFTWARE")
* RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE PROVIDED TO RECEIVER ON
* AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY DISCLAIMS ANY AND ALL WARRANTIES,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR NONINFRINGEMENT.
* NEITHER DOES MEDIATEK PROVIDE ANY WARRANTY WHATSOEVER WITH RESPECT TO THE
* SOFTWARE OF ANY THIRD PARTY WHICH MAY BE USED BY, INCORPORATED IN, OR
* SUPPLIED WITH THE MEDIATEK SOFTWARE, AND RECEIVER AGREES TO LOOK ONLY TO SUCH
* THIRD PARTY FOR ANY WARRANTY CLAIM RELATING THERETO. RECEIVER EXPRESSLY ACKNOWLEDGES
* THAT IT IS RECEIVER'S SOLE RESPONSIBILITY TO OBTAIN FROM ANY THIRD PARTY ALL PROPER LICENSES
* CONTAINED IN MEDIATEK SOFTWARE. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE FOR ANY MEDIATEK
* SOFTWARE RELEASES MADE TO RECEIVER'S SPECIFICATION OR TO CONFORM TO A PARTICULAR
* STANDARD OR OPEN FORUM. RECEIVER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S ENTIRE AND
* CUMULATIVE LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE RELEASED HEREUNDER WILL BE,
* AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE MEDIATEK SOFTWARE AT ISSUE,
* OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE CHARGE PAID BY RECEIVER TO
* MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE.
*
* The following software/firmware and/or related documentation ("MediaTek Software")
* have been modified by MediaTek Inc. All revisions are subject to any receiver's
* applicable license agreements with MediaTek Inc.
*/
/*
* Copyright (C) 2007 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.music;
// mtk80658: add for Music lyrics supporting
import java.util.Scanner;
import java.util.regex.Pattern;
// mtk80658
import com.android.music.R;
import com.android.music.MusicUtils.ServiceToken;
import android.app.Activity;
import android.app.AlertDialog;
import android.app.KeyguardManager;
import android.app.SearchManager;
import android.content.ActivityNotFoundException;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.ContentResolver;
import android.content.ContentUris;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.ServiceConnection;
import android.content.pm.ResolveInfo;
import android.content.res.Configuration;
import android.database.Cursor;
import android.graphics.Bitmap;
import android.media.audiofx.AudioEffect;
import android.media.AudioManager;
import android.net.Uri;
import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
import android.os.Looper;
import android.os.Message;
import android.os.RemoteException;
import android.os.SystemClock;
import android.provider.MediaStore;
import android.text.Layout;
import android.text.TextUtils.TruncateAt;
import android.util.Log;
import android.view.KeyEvent;
import android.view.Menu;
import android.view.MenuItem;
import android.view.MotionEvent;
import android.view.SubMenu;
import android.view.View;
import android.view.ViewConfiguration;
import android.view.Window;
import android.view.View.OnTouchListener;
import android.view.ViewGroup.LayoutParams;
import android.widget.Button;
import android.widget.FrameLayout;
import android.widget.ImageButton;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.ProgressBar;
import android.widget.SeekBar;
import android.widget.TextView;
import android.widget.Toast;
import android.widget.SeekBar.OnSeekBarChangeListener;
import android.app.StatusBarManager;
import com.mediatek.featureoption.FeatureOption;
import android.drm.*;
public class MediaPlaybackActivity extends Activity implements MusicUtils.Defs,
View.OnTouchListener, View.OnLongClickListener
{
private static final String TAG = "MediaPlaybackActivity";
private static final int USE_AS_RINGTONE = CHILD_MENU_BASE;
private boolean mSeeking = false;
private boolean mDeviceHasDpad;
private long mStartSeekPos = 0;
private long mLastSeekEventTime;
private IMediaPlaybackService mService = null;
private RepeatingImageButton mPrevButton;
private ImageButton mPauseButton;
private RepeatingImageButton mNextButton;
private ImageButton mRepeatButton;
private ImageButton mShuffleButton;
private ImageButton mQueueButton;
private Worker mAlbumArtWorker;
private AlbumArtHandler mAlbumArtHandler;
private Toast mToast;
private int mTouchSlop;
private SubMenu mAddToPlaylistSubmenu;
private boolean isOFNDown = false;
/**
* Some music's durations can only be obtained when playing the media.
* As a result we must know whether to update the durations.
*/
private boolean mNeedUpdateDuration = true;
private ServiceToken mToken;
// mtk80658: add for Music lyrics supporting
private ScrollLrcView mScrollLrcView = null;
private boolean mLrcReady = false;
private boolean mScrollLrcReady = false;
private int mLrcMode = ScrollLrcView.LRC_MODE_SINGLE;
// mtk80658
public MediaPlaybackActivity()
{
}
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle icicle)
{
super.onCreate(icicle);
setVolumeControlStream(AudioManager.STREAM_MUSIC);
mAlbumArtWorker = new Worker("album art worker");
mAlbumArtHandler = new AlbumArtHandler(mAlbumArtWorker.getLooper());
requestWindowFeature(Window.FEATURE_NO_TITLE);
// mtk80658: modified for Music lyrics supporting
// load the layout integrated with Lyrics module when MTK_MUSIC_LRC_SUPPORT enabled
if (FeatureOption.MTK_MUSIC_LRC_SUPPORT) {
setContentView(R.layout.audio_player_with_lrc);
} else {
setContentView(R.layout.audio_player); // default layout without lyrics module
}
// mtk80658
mCurrentTime = (TextView) findViewById(R.id.currenttime);
mTotalTime = (TextView) findViewById(R.id.totaltime);
mProgress = (ProgressBar) findViewById(android.R.id.progress);
mAlbum = (ImageView) findViewById(R.id.album);
mArtistName = (TextView) findViewById(R.id.artistname);
mAlbumName = (TextView) findViewById(R.id.albumname);
mTrackName = (TextView) findViewById(R.id.trackname);
View v = (View)mArtistName.getParent();
v.setOnTouchListener(this);
v.setOnLongClickListener(this);
v = (View)mAlbumName.getParent();
v.setOnTouchListener(this);
v.setOnLongClickListener(this);
v = (View)mTrackName.getParent();
v.setOnTouchListener(this);
v.setOnLongClickListener(this);
mPrevButton = (RepeatingImageButton) findViewById(R.id.prev);
mPrevButton.setOnClickListener(mPrevListener);
mPrevButton.setRepeatListener(mRewListener, 260);
mPauseButton = (ImageButton) findViewById(R.id.pause);
mPauseButton.requestFocus();
mPauseButton.setOnClickListener(mPauseListener);
mNextButton = (RepeatingImageButton) findViewById(R.id.next);
mNextButton.setOnClickListener(mNextListener);
mNextButton.setRepeatListener(mFfwdListener, 260);
seekmethod = 1;
// mtk80658: add for Music lyrics supporting
if (FeatureOption.MTK_MUSIC_LRC_SUPPORT) {
// initialize lyrics view
mLrcMode = MusicUtils.getIntPref(this, "lyricMode", ScrollLrcView.LRC_MODE_SINGLE);
mScrollLrcView = (ScrollLrcView) findViewById(R.id.lyrics_view);
// disable the touch event (that the scroll view can't be scroll by finger move)
mScrollLrcView.setOnTouchListener(new OnTouchListener() {
public boolean onTouch(View v, MotionEvent event) {
return true;
}
});
// the imageview that is clickable. for swithing between single-line / multiple-line mode
((ImageView) findViewById(R.id.lyrics_shift)).setOnClickListener (
new View.OnClickListener () {
public void onClick(View v) {
if (mLrcMode == ScrollLrcView.LRC_MODE_MULTIPLE) {
mLrcMode = ScrollLrcView.LRC_MODE_SINGLE;
} else if (mLrcMode == ScrollLrcView.LRC_MODE_SINGLE) {
mLrcMode = ScrollLrcView.LRC_MODE_MULTIPLE;
}
// alps00061113, the preference should be saved immediately here,
// otherwise it will return in the "try" block below
MusicUtils.setIntPref(MediaPlaybackActivity.this, "lyricMode", mLrcMode);
updateLyricsFrame();
try {
if (!mScrollLrcView.reSetupLyrics(
MediaPlaybackActivity.this, mLrcMode, (int)mService.position())) {
return;
}
} catch (RemoteException ex) {
throw new LrcScrollException();
}
mHandler.sendEmptyMessage(UPDATE_LRC);
}
}
);
} // if (FeatureOption.MTK_MUSIC_LRC_SUPPORT)
// mtk80658
mDeviceHasDpad = (getResources().getConfiguration().navigation ==
Configuration.NAVIGATION_DPAD);
mQueueButton = (ImageButton) findViewById(R.id.curplaylist);
mQueueButton.setOnClickListener(mQueueListener);
mShuffleButton = ((ImageButton) findViewById(R.id.shuffle));
mShuffleButton.setOnClickListener(mShuffleListener);
mRepeatButton = ((ImageButton) findViewById(R.id.repeat));
mRepeatButton.setOnClickListener(mRepeatListener);
if (mProgress instanceof SeekBar) {
SeekBar seeker = (SeekBar) mProgress;
seeker.setOnSeekBarChangeListener(mSeekListener);
}
mProgress.setMax(1000);
mTouchSlop = ViewConfiguration.get(this).getScaledTouchSlop();
}
int mInitialX = -1;
int mLastX = -1;
int mTextWidth = 0;
int mViewWidth = 0;
boolean mDraggingLabel = false;
TextView textViewForContainer(View v) {
View vv = v.findViewById(R.id.artistname);
if (vv != null) return (TextView) vv;
vv = v.findViewById(R.id.albumname);
if (vv != null) return (TextView) vv;
vv = v.findViewById(R.id.trackname);
if (vv != null) return (TextView) vv;
return null;
}
public boolean onTouch(View v, MotionEvent event) {
int action = event.getAction();
TextView tv = textViewForContainer(v);
if (tv == null) {
return false;
}
if (action == MotionEvent.ACTION_DOWN) {
v.setBackgroundColor(0xff606060);
mInitialX = mLastX = (int) event.getX();
mDraggingLabel = false;
} else if (action == MotionEvent.ACTION_UP ||
action == MotionEvent.ACTION_CANCEL) {
v.setBackgroundColor(0);
if (mDraggingLabel) {
Message msg = mLabelScroller.obtainMessage(0, tv);
mLabelScroller.sendMessageDelayed(msg, 1000);
}
} else if (action == MotionEvent.ACTION_MOVE) {
if (mDraggingLabel) {
int scrollx = tv.getScrollX();
int x = (int) event.getX();
int delta = mLastX - x;
if (delta != 0) {
mLastX = x;
scrollx += delta;
if (scrollx > mTextWidth) {
// scrolled the text completely off the view to the left
scrollx -= mTextWidth;
scrollx -= mViewWidth;
}
if (scrollx < -mViewWidth) {
// scrolled the text completely off the view to the right
scrollx += mViewWidth;
scrollx += mTextWidth;
}
tv.scrollTo(scrollx, 0);
}
return true;
}
int delta = mInitialX - (int) event.getX();
if (Math.abs(delta) > mTouchSlop) {
// start moving
mLabelScroller.removeMessages(0, tv);
// Only turn ellipsizing off when it's not already off, because it
// causes the scroll position to be reset to 0.
if (tv.getEllipsize() != null) {
tv.setEllipsize(null);
}
Layout ll = tv.getLayout();
// layout might be null if the text just changed, or ellipsizing
// was just turned off
if (ll == null) {
return false;
}
// get the non-ellipsized line width, to determine whether scrolling
// should even be allowed
mTextWidth = (int) tv.getLayout().getLineWidth(0);
mViewWidth = tv.getWidth();
if (mViewWidth > mTextWidth) {
tv.setEllipsize(TruncateAt.END);
v.cancelLongPress();
return false;
}
mDraggingLabel = true;
tv.setHorizontalFadingEdgeEnabled(true);
v.cancelLongPress();
return true;
}
}
return false;
}
Handler mLabelScroller = new Handler() {
@Override
public void handleMessage(Message msg) {
TextView tv = (TextView) msg.obj;
int x = tv.getScrollX();
x = x * 3 / 4;
tv.scrollTo(x, 0);
if (x == 0) {
tv.setEllipsize(TruncateAt.END);
} else {
Message newmsg = obtainMessage(0, tv);
mLabelScroller.sendMessageDelayed(newmsg, 15);
}
}
};
public boolean onLongClick(View view) {
CharSequence title = null;
String mime = null;
String query = null;
String artist;
String album;
String song;
long audioid;
try {
artist = mService.getArtistName();
album = mService.getAlbumName();
song = mService.getTrackName();
audioid = mService.getAudioId();
} catch (RemoteException ex) {
return true;
} catch (NullPointerException ex) {
// we might not actually have the service yet
return true;
}
if (MediaStore.UNKNOWN_STRING.equals(album) &&
MediaStore.UNKNOWN_STRING.equals(artist) &&
song != null &&
song.startsWith("recording")) {
// not music
return false;
}
if (audioid < 0) {
return false;
}
Cursor c = MusicUtils.query(this,
ContentUris.withAppendedId(MediaStore.Audio.Media.EXTERNAL_CONTENT_URI, audioid),
new String[] {MediaStore.Audio.Media.IS_MUSIC}, null, null, null);
boolean ismusic = true;
if (c != null) {
if (c.moveToFirst()) {
ismusic = c.getInt(0) != 0;
}
c.close();
}
if (!ismusic) {
return false;
}
boolean knownartist =
(artist != null) && !MediaStore.UNKNOWN_STRING.equals(artist);
boolean knownalbum =
(album != null) && !MediaStore.UNKNOWN_STRING.equals(album);
if (knownartist && view.equals(mArtistName.getParent())) {
title = artist;
query = artist;
mime = MediaStore.Audio.Artists.ENTRY_CONTENT_TYPE;
} else if (knownalbum && view.equals(mAlbumName.getParent())) {
title = album;
if (knownartist) {
query = artist + " " + album;
} else {
query = album;
}
mime = MediaStore.Audio.Albums.ENTRY_CONTENT_TYPE;
} else if (view.equals(mTrackName.getParent()) || !knownartist || !knownalbum) {
if ((song == null) || MediaStore.UNKNOWN_STRING.equals(song)) {
// A popup of the form "Search for null/'' using ..." is pretty
// unhelpful, plus, we won't find any way to buy it anyway.
return true;
}
title = song;
if (knownartist) {
query = artist + " " + song;
} else {
query = song;
}
mime = "audio/*"; // the specific type doesn't matter, so don't bother retrieving it
} else {
throw new RuntimeException("shouldn't be here");
}
title = getString(R.string.mediasearch, title);
Intent i = new Intent();
i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
i.setAction(MediaStore.INTENT_ACTION_MEDIA_SEARCH);
i.putExtra(SearchManager.QUERY, query);
if(knownartist) {
i.putExtra(MediaStore.EXTRA_MEDIA_ARTIST, artist);
}
if(knownalbum) {
i.putExtra(MediaStore.EXTRA_MEDIA_ALBUM, album);
}
i.putExtra(MediaStore.EXTRA_MEDIA_TITLE, song);
i.putExtra(MediaStore.EXTRA_MEDIA_FOCUS, mime);
startActivity(Intent.createChooser(i, title));
return true;
}
/**
* New position to seek to, in miliseconds.
*/
private long mPositionToSeek;
private OnSeekBarChangeListener mSeekListener = new OnSeekBarChangeListener() {
public void onStartTrackingTouch(SeekBar bar) {
//mLastSeekEventTime = 0;
mFromTouch = true;
}
public void onProgressChanged(SeekBar bar, int progress, boolean fromuser) {
if (!fromuser || (mService == null)) return;
//long now = SystemClock.elapsedRealtime();
//if (!mFromTouch && (now - mLastSeekEventTime) > 250) {
// mLastSeekEventTime = now;
// mPositionToSeek = mDuration * progress / 1000;
// morris yang 0407 [
/*
try {
mService.seek(mPosOverride);
} catch (RemoteException ex) {
}
*/
// ]
// trackball event, allow progress updates
//}
if (!mFromTouch) {
mPositionToSeek = mDuration * progress / 1000;
mPosOverride = mPositionToSeek;
try {
mService.seek(mPositionToSeek);
} catch (RemoteException ex) {
}
refreshNow();
mPosOverride = -1;
}
}
public void onStopTrackingTouch(SeekBar bar) {
// morris yang 0407 [
if (mService != null) {
try {
//mService.seek(mPositionToSeek);
mPositionToSeek = bar.getProgress() * mDuration / 1000;
mPosOverride = mPositionToSeek;
mService.seek(mPositionToSeek);
refreshNow();
} catch (RemoteException ex) {
}
}
// ]
mPosOverride = -1;
mFromTouch = false;
}
};
private View.OnClickListener mQueueListener = new View.OnClickListener() {
public void onClick(View v) {
startActivity(
new Intent(Intent.ACTION_EDIT)
.setDataAndType(Uri.EMPTY, "vnd.android.cursor.dir/track")
.putExtra("playlist", "nowplaying")
);
}
};
private View.OnClickListener mShuffleListener = new View.OnClickListener() {
public void onClick(View v) {
toggleShuffle();
}
};
private View.OnClickListener mRepeatListener = new View.OnClickListener() {
public void onClick(View v) {
cycleRepeat();
}
};
private View.OnClickListener mPauseListener = new View.OnClickListener() {
public void onClick(View v) {
doPauseResume();
}
};
private View.OnClickListener mPrevListener = new View.OnClickListener() {
public void onClick(View v) {
if (mService == null) return;
try {
if (mService.position() < 2000) {
//added by qingfu.su@archermind.com
mPosOverride = -1;
//added by qingfu.su@archermind.com end
mService.prev();
} else {
mService.seek(0);
//added by qingfu.su@archermind.com
mPosOverride = -1;
//added by qingfu.su@archermind.com end
mService.play();
}
} catch (RemoteException ex) {
}
}
};
private View.OnClickListener mNextListener = new View.OnClickListener() {
public void onClick(View v) {
if (mService == null) return;
try {
mService.next();
//added by qingfu.su@archermind.com
mPosOverride = -1;
//added by qingfu.su@archermind.com end
} catch (RemoteException ex) {
}
}
};
private RepeatingImageButton.RepeatListener mRewListener =
new RepeatingImageButton.RepeatListener() {
public void onRepeat(View v, long howlong, int repcnt) {
scanBackward(repcnt, howlong);
}
};
private RepeatingImageButton.RepeatListener mFfwdListener =
new RepeatingImageButton.RepeatListener() {
public void onRepeat(View v, long howlong, int repcnt) {
scanForward(repcnt, howlong);
}
};
@Override
public void onStop() {
paused = true;
mHandler.removeMessages(REFRESH);
unregisterReceiver(mStatusListener);
unregisterReceiver(mUnmountReceiver);
MusicUtils.unbindFromService(mToken);
mService = null;
super.onStop();
}
@Override
public void onStart() {
super.onStart();
paused = false;
mToken = MusicUtils.bindToService(this, osc);
if (mToken == null) {
// something went wrong
mHandler.sendEmptyMessage(QUIT);
}
IntentFilter f = new IntentFilter();
f.addAction(MediaPlaybackService.PLAYSTATE_CHANGED);
f.addAction(MediaPlaybackService.META_CHANGED);
f.addAction(MediaPlaybackService.QUIT_PLAYBACK);
f.addAction(Intent.ACTION_SCREEN_ON);
f.addAction(Intent.ACTION_SCREEN_OFF);
registerReceiver(mStatusListener, new IntentFilter(f));
f = new IntentFilter();
f.addAction(Intent.ACTION_MEDIA_EJECT);
f.addDataScheme("file");
registerReceiver(mUnmountReceiver, f);
updateTrackInfo();
long next = refreshNow();
queueNextRefresh(next);
}
@Override
public void onNewIntent(Intent intent) {
setIntent(intent);
}
@Override
public void onResume() {
super.onResume();
Intent i = getIntent();
boolean collapseStatusBar = i.getBooleanExtra("collapse_statusbar", false);
Log.d(TAG, "onResume: collapseStatusBar=" + collapseStatusBar);
if (collapseStatusBar) {
StatusBarManager statusBar = (StatusBarManager)getSystemService(Context.STATUS_BAR_SERVICE);
statusBar.collapse();
}
updateTrackInfo();
setPauseButtonImage();
// When back to this activity, ask service for right position
mPosOverride = -1;
// mtk80658, add for Music lyrics supporting
if (FeatureOption.MTK_MUSIC_LRC_SUPPORT) {
if (null != mScrollLrcView) {
mScrollLrcView.resetHighlight();
}
}
// mtk80658
}
@Override
public void onDestroy()
{
mAlbumArtWorker.quit();
super.onDestroy();
//System.out.println("***************** playback activity onDestroy\n");
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
super.onCreateOptionsMenu(menu);
// Don't show the menu items if we got launched by path/filedescriptor, or
// if we're in one shot mode. In most cases, these menu items are not
// useful in those modes, so for consistency we never show them in these
// modes, instead of tailoring them to the specific file being played.
long currentAudioId = MusicUtils.getCurrentAudioId();
if (currentAudioId >= 0) {
menu.add(0, GOTO_START, 0, R.string.goto_start).setIcon(R.drawable.ic_menu_music_library);
menu.add(0, PARTY_SHUFFLE, 0, R.string.party_shuffle); // icon will be set in onPrepareOptionsMenu()
// get the object for method onPrepareOptionsMenu to keep playlist menu up-to-date
mAddToPlaylistSubmenu = menu.addSubMenu(0, ADD_TO_PLAYLIST, 0,
R.string.add_to_playlist).setIcon(android.R.drawable.ic_menu_add);
// these next two are in a separate group, so they can be shown/hidden as needed
// based on the keyguard state
if (FeatureOption.MTK_DRM_APP) {
Cursor c = getContentResolver().query(
ContentUris.withAppendedId(MediaStore.Audio.Media.EXTERNAL_CONTENT_URI, currentAudioId),
new String[] {MediaStore.Audio.Media.IS_DRM, MediaStore.Audio.Media.DRM_METHOD}, null, null, null);
int isDRM = -1;
int drmMethod = -1;
if (c != null && c.getCount() == 1) {
c.moveToFirst();
isDRM = c.getInt(0);
drmMethod = c.getInt(1);
}
if (c != null)
c.close();
if (isDRM != 1 || (isDRM == 1 && drmMethod == DrmStore.DrmMethod.METHOD_FL)) {
menu.add(1, USE_AS_RINGTONE, 0, R.string.ringtone_menu_short)
.setIcon(R.drawable.ic_menu_set_as_ringtone);
}
} else {
menu.add(1, USE_AS_RINGTONE, 0, R.string.ringtone_menu_short)
.setIcon(R.drawable.ic_menu_set_as_ringtone);
}
menu.add(1, DELETE_ITEM, 0, R.string.delete_item)
.setIcon(R.drawable.ic_menu_delete);
Intent i = new Intent(AudioEffect.ACTION_DISPLAY_AUDIO_EFFECT_CONTROL_PANEL);
if (getPackageManager().resolveActivity(i, 0) != null) {
menu.add(0, EFFECTS_PANEL, 0, R.string.effects_list_title).setIcon(R.drawable.ic_menu_eq);
}
if (FeatureOption.MTK_FM_TX_SUPPORT) {
SubMenu fmSettingItem;
fmSettingItem= menu.addSubMenu (1,Menu.NONE,0,R.string.music_settings).setIcon(com.android.internal.R.drawable.ic_menu_preferences);//setIcon(R.drawable.ic_settings_fm);
fmSettingItem.add(0, FM_TRANSMITTER, 0, R.string.music_fm_transmiter);
}
return true;
}
return false;
}
@Override
public boolean onPrepareOptionsMenu(Menu menu) {
if (mService == null) return false;
MenuItem item = menu.findItem(PARTY_SHUFFLE);
if (item != null) {
int shuffle = MusicUtils.getCurrentShuffleMode();
if (shuffle == MediaPlaybackService.SHUFFLE_AUTO) {
item.setIcon(R.drawable.ic_menu_party_shuffle);
item.setTitle(R.string.party_shuffle_off);
} else {
item.setIcon(R.drawable.ic_menu_party_shuffle);
item.setTitle(R.string.party_shuffle);
}
}
// Keep the playlist menu up-to-date
MusicUtils.makePlaylistMenu(this, mAddToPlaylistSubmenu);
KeyguardManager km = (KeyguardManager) getSystemService(Context.KEYGUARD_SERVICE);
menu.setGroupVisible(1, !km.inKeyguardRestrictedInputMode());
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
Intent intent;
try {
switch (item.getItemId()) {
case GOTO_START:
intent = new Intent();
intent.setClass(this, MusicBrowserActivity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent);
finish();
break;
case USE_AS_RINGTONE: {
// Set the system setting to make this the current ringtone
if (mService != null) {
MusicUtils.setRingtone(this, mService.getAudioId());
}
return true;
}
case PARTY_SHUFFLE:
MusicUtils.togglePartyShuffle();
setShuffleButtonImage();
break;
case NEW_PLAYLIST: {
intent = new Intent();
intent.setClass(this, CreatePlaylist.class);
startActivityForResult(intent, NEW_PLAYLIST);
return true;
}
case PLAYLIST_SELECTED: {
long [] list = new long[1];
list[0] = MusicUtils.getCurrentAudioId();
long playlist = item.getIntent().getLongExtra("playlist", 0);
MusicUtils.addToPlaylist(this, list, playlist);
return true;
}
case DELETE_ITEM: {
if (mService != null) {
long [] list = new long[1];
list[0] = MusicUtils.getCurrentAudioId();
Bundle b = new Bundle();
String f;
if (android.os.Environment.isExternalStorageRemovable()) {
f = getString(R.string.delete_song_desc, mService.getTrackName());
} else {
f = getString(R.string.delete_song_desc_nosdcard, mService.getTrackName());
}
b.putString("description", f);
b.putLongArray("items", list);
intent = new Intent();
intent.setClass(this, DeleteItems.class);
intent.putExtras(b);
startActivityForResult(intent, -1);
}
return true;
}
case EFFECTS_PANEL: {
Intent i = new Intent(AudioEffect.ACTION_DISPLAY_AUDIO_EFFECT_CONTROL_PANEL);
i.putExtra(AudioEffect.EXTRA_AUDIO_SESSION, mService.getAudioSessionId());
startActivityForResult(i, EFFECTS_PANEL);
return true;
}
case FM_TRANSMITTER:{
if (FeatureOption.MTK_FM_TX_SUPPORT) {
Intent intentFMTx = new Intent("com.mediatek.FMTransmitter.FMTransmitterActivity");
intentFMTx.setClassName("com.mediatek.FMTransmitter", "com.mediatek.FMTransmitter.FMTransmitterActivity");
try {
startActivity(intentFMTx);
} catch (ActivityNotFoundException anfe) {
Log.e("MediaPlaybackActivity", "FM Tx activity is not found on this phone!!");
}
}
return true;
}
}
} catch (RemoteException ex) {
}
return super.onOptionsItemSelected(item);
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent intent) {
if (resultCode != RESULT_OK) {
return;
}
switch (requestCode) {
case NEW_PLAYLIST:
Uri uri = intent.getData();
if (uri != null) {
long [] list = new long[1];
list[0] = MusicUtils.getCurrentAudioId();
int playlist = Integer.parseInt(uri.getLastPathSegment());
MusicUtils.addToPlaylist(this, list, playlist);
}
break;
}
}
private final int keyboard[][] = {
{
KeyEvent.KEYCODE_Q,
KeyEvent.KEYCODE_W,
KeyEvent.KEYCODE_E,
KeyEvent.KEYCODE_R,
KeyEvent.KEYCODE_T,
KeyEvent.KEYCODE_Y,
KeyEvent.KEYCODE_U,
KeyEvent.KEYCODE_I,
KeyEvent.KEYCODE_O,
KeyEvent.KEYCODE_P,
},
{
KeyEvent.KEYCODE_A,
KeyEvent.KEYCODE_S,
KeyEvent.KEYCODE_D,
KeyEvent.KEYCODE_F,
KeyEvent.KEYCODE_G,
KeyEvent.KEYCODE_H,
KeyEvent.KEYCODE_J,
KeyEvent.KEYCODE_K,
KeyEvent.KEYCODE_L,
KeyEvent.KEYCODE_DEL,
},
{
KeyEvent.KEYCODE_Z,
KeyEvent.KEYCODE_X,
KeyEvent.KEYCODE_C,
KeyEvent.KEYCODE_V,
KeyEvent.KEYCODE_B,
KeyEvent.KEYCODE_N,
KeyEvent.KEYCODE_M,
KeyEvent.KEYCODE_COMMA,
KeyEvent.KEYCODE_PERIOD,
KeyEvent.KEYCODE_ENTER
}
};
private int lastX;
private int lastY;
private boolean seekMethod1(int keyCode)
{
if (mService == null) return false;
for(int x=0;x<10;x++) {
for(int y=0;y<3;y++) {
if(keyboard[y][x] == keyCode) {
int dir = 0;
// top row
if(x == lastX && y == lastY) dir = 0;
else if (y == 0 && lastY == 0 && x > lastX) dir = 1;
else if (y == 0 && lastY == 0 && x < lastX) dir = -1;
// bottom row
else if (y == 2 && lastY == 2 && x > lastX) dir = -1;
else if (y == 2 && lastY == 2 && x < lastX) dir = 1;
// moving up
else if (y < lastY && x <= 4) dir = 1;
else if (y < lastY && x >= 5) dir = -1;
// moving down
else if (y > lastY && x <= 4) dir = -1;
else if (y > lastY && x >= 5) dir = 1;
lastX = x;
lastY = y;
try {
mService.seek(mService.position() + dir * 5);
} catch (RemoteException ex) {
}
refreshNow();
return true;
}
}
}
lastX = -1;
lastY = -1;
return false;
}
private boolean seekMethod2(int keyCode)
{
if (mService == null) return false;
for(int i=0;i<10;i++) {
if(keyboard[0][i] == keyCode) {
int seekpercentage = 100*i/10;
try {
mService.seek(mService.duration() * seekpercentage / 100);
} catch (RemoteException ex) {
}
refreshNow();
return true;
}
}
return false;
}
@Override
public boolean onKeyUp(int keyCode, KeyEvent event) {
try {
switch(keyCode)
{
case KeyEvent.KEYCODE_DPAD_LEFT:
if (!useDpadMusicControl()) {
break;
}
if (mService != null) {
if (!mSeeking && mStartSeekPos >= 0) {
mPauseButton.requestFocus();
if (mStartSeekPos < 1000) {
mService.prev();
} else {
mService.seek(0);
}
} else {
scanBackward(-1, event.getEventTime() - event.getDownTime());
mPauseButton.requestFocus();
mStartSeekPos = -1;
}
}
mSeeking = false;
mPosOverride = -1;
return true;
case KeyEvent.KEYCODE_DPAD_RIGHT:
if (!useDpadMusicControl()) {
break;
}
if (mService != null) {
if (!mSeeking && mStartSeekPos >= 0) {
mPauseButton.requestFocus();
mService.next();
} else {
scanForward(-1, event.getEventTime() - event.getDownTime());
mPauseButton.requestFocus();
mStartSeekPos = -1;
}
}
mSeeking = false;
mPosOverride = -1;
return true;
case KeyEvent.KEYCODE_DPAD_CENTER:
View curSel = getCurrentFocus();
if((curSel !=null && R.id.pause == curSel.getId()) || (curSel == null)){
doPauseResume();
}
return true;
}
} catch (RemoteException ex) {
}
return super.onKeyUp(keyCode, event);
}
private boolean useDpadMusicControl() {
if (mDeviceHasDpad && (mPrevButton.isFocused() ||
mNextButton.isFocused() ||
mPauseButton.isFocused())) {
return true;
}
return false;
}
@Override
public boolean onKeyDown(int keyCode, KeyEvent event)
{
int direction = -1;
int repcnt = event.getRepeatCount();
if((seekmethod==0)?seekMethod1(keyCode):seekMethod2(keyCode))
return true;
switch(keyCode)
{
/*
// image scale
case KeyEvent.KEYCODE_Q: av.adjustParams(-0.05, 0.0, 0.0, 0.0, 0.0,-1.0); break;
case KeyEvent.KEYCODE_E: av.adjustParams( 0.05, 0.0, 0.0, 0.0, 0.0, 1.0); break;
// image translate
case KeyEvent.KEYCODE_W: av.adjustParams( 0.0, 0.0,-1.0, 0.0, 0.0, 0.0); break;
case KeyEvent.KEYCODE_X: av.adjustParams( 0.0, 0.0, 1.0, 0.0, 0.0, 0.0); break;
case KeyEvent.KEYCODE_A: av.adjustParams( 0.0,-1.0, 0.0, 0.0, 0.0, 0.0); break;
case KeyEvent.KEYCODE_D: av.adjustParams( 0.0, 1.0, 0.0, 0.0, 0.0, 0.0); break;
// camera rotation
case KeyEvent.KEYCODE_R: av.adjustParams( 0.0, 0.0, 0.0, 0.0, 0.0,-1.0); break;
case KeyEvent.KEYCODE_U: av.adjustParams( 0.0, 0.0, 0.0, 0.0, 0.0, 1.0); break;
// camera translate
case KeyEvent.KEYCODE_Y: av.adjustParams( 0.0, 0.0, 0.0, 0.0,-1.0, 0.0); break;
case KeyEvent.KEYCODE_N: av.adjustParams( 0.0, 0.0, 0.0, 0.0, 1.0, 0.0); break;
case KeyEvent.KEYCODE_G: av.adjustParams( 0.0, 0.0, 0.0,-1.0, 0.0, 0.0); break;
case KeyEvent.KEYCODE_J: av.adjustParams( 0.0, 0.0, 0.0, 1.0, 0.0, 0.0); break;
*/
case KeyEvent.KEYCODE_SLASH:
seekmethod = 1 - seekmethod;
return true;
case KeyEvent.KEYCODE_DPAD_LEFT:
if (!useDpadMusicControl()) {
break;
}
if (!mPrevButton.hasFocus()) {
mPrevButton.requestFocus();
}
scanBackward(repcnt, event.getEventTime() - event.getDownTime());
return true;
case KeyEvent.KEYCODE_DPAD_RIGHT:
if (!useDpadMusicControl()) {
break;
}
if (!mNextButton.hasFocus()) {
mNextButton.requestFocus();
}
scanForward(repcnt, event.getEventTime() - event.getDownTime());
return true;
case KeyEvent.KEYCODE_S:
toggleShuffle();
return true;
case KeyEvent.KEYCODE_DPAD_CENTER:
return true;
case KeyEvent.KEYCODE_SPACE:
doPauseResume();
return true;
}
return super.onKeyDown(keyCode, event);
}
private void scanBackward(int repcnt, long delta) {
if(mService == null) return;
try {
if(repcnt == 0) {
mStartSeekPos = mService.position();
mLastSeekEventTime = 0;
mSeeking = false;
} else {
mSeeking = true;
if (delta < 5000) {
// seek at 10x speed for the first 5 seconds
delta = delta * 10;
} else {
// seek at 40x after that
delta = 50000 + (delta - 5000) * 40;
}
long newpos = mStartSeekPos - delta;
if (newpos < 0) {
// move to previous track
mService.prev();
long duration = mService.duration();
mStartSeekPos += duration;
newpos += duration;
}
if (((delta - mLastSeekEventTime) > 250) || repcnt < 0){
mService.seek(newpos);
mLastSeekEventTime = delta;
}
if (repcnt >= 0) {
mPosOverride = newpos;
} else {
mPosOverride = -1;
}
refreshNow();
}
} catch (RemoteException ex) {
}
}
private void scanForward(int repcnt, long delta) {
if(mService == null) return;
try {
if(repcnt == 0) {
mStartSeekPos = mService.position();
mLastSeekEventTime = 0;
mSeeking = false;
} else {
mSeeking = true;
if (delta < 5000) {
// seek at 10x speed for the first 5 seconds
delta = delta * 10;
} else {
// seek at 40x after that
delta = 50000 + (delta - 5000) * 40;
}
long newpos = mStartSeekPos + delta;
long duration = mService.duration();
if (newpos >= duration) {
// move to next track
mService.next();
mStartSeekPos -= duration; // is OK to go negative
newpos -= duration;
}
if (((delta - mLastSeekEventTime) > 250) || repcnt < 0){
mService.seek(newpos);
mLastSeekEventTime = delta;
}
if (repcnt >= 0) {
mPosOverride = newpos;
} else {
mPosOverride = -1;
}
refreshNow();
}
} catch (RemoteException ex) {
}
}
private void doPauseResume() {
try {
Log.d(TAG, "doPauseResume: " + (mService == null ? "mService=null" : ("isPlaying=" + mService.isPlaying())));
if(mService != null) {
if (mService.isPlaying()) {
mPosOverride = mService.position();
mService.pause();
} else {
mService.play();
mPosOverride = -1;
}
refreshNow();
setPauseButtonImage();
}
} catch (RemoteException ex) {
}
}
private void toggleShuffle() {
if (mService == null) {
return;
}
try {
int shuffle = mService.getShuffleMode();
if (shuffle == MediaPlaybackService.SHUFFLE_NONE) {
mService.setShuffleMode(MediaPlaybackService.SHUFFLE_NORMAL);
if (mService.getRepeatMode() == MediaPlaybackService.REPEAT_CURRENT) {
mService.setRepeatMode(MediaPlaybackService.REPEAT_ALL);
setRepeatButtonImage();
}
showToast(R.string.shuffle_on_notif);
} else if (shuffle == MediaPlaybackService.SHUFFLE_NORMAL ||
shuffle == MediaPlaybackService.SHUFFLE_AUTO) {
mService.setShuffleMode(MediaPlaybackService.SHUFFLE_NONE);
showToast(R.string.shuffle_off_notif);
} else {
Log.e("MediaPlaybackActivity", "Invalid shuffle mode: " + shuffle);
}
setShuffleButtonImage();
} catch (RemoteException ex) {
}
}
private void cycleRepeat() {
if (mService == null) {
return;
}
try {
int mode = mService.getRepeatMode();
if (mode == MediaPlaybackService.REPEAT_NONE) {
mService.setRepeatMode(MediaPlaybackService.REPEAT_ALL);
showToast(R.string.repeat_all_notif);
} else if (mode == MediaPlaybackService.REPEAT_ALL) {
mService.setRepeatMode(MediaPlaybackService.REPEAT_CURRENT);
if (mService.getShuffleMode() != MediaPlaybackService.SHUFFLE_NONE) {
mService.setShuffleMode(MediaPlaybackService.SHUFFLE_NONE);
setShuffleButtonImage();
}
showToast(R.string.repeat_current_notif);
} else {
mService.setRepeatMode(MediaPlaybackService.REPEAT_NONE);
showToast(R.string.repeat_off_notif);
}
setRepeatButtonImage();
} catch (RemoteException ex) {
}
}
private void showToast(int resid) {
if (mToast == null) {
mToast = Toast.makeText(this, "", Toast.LENGTH_SHORT);
}
mToast.setText(resid);
mToast.show();
}
private void startPlayback() {
if(mService == null)
return;
Intent intent = getIntent();
String filename = "";
Uri uri = intent.getData();
if (uri != null && uri.toString().length() > 0) {
// If this is a file:// URI, just use the path directly instead
// of going through the open-from-filedescriptor codepath.
String scheme = uri.getScheme();
if ("file".equals(scheme)) {
filename = uri.getPath();
} else {
filename = uri.toString();
}
try {
mService.stop();
mService.openFile(filename);
mService.play();
setIntent(new Intent());
} catch (Exception ex) {
Log.d("MediaPlaybackActivity", "couldn't start playback: " + ex);
}
}
updateTrackInfo();
// mtk80658: add for Music lyrics supporting
if (FeatureOption.MTK_MUSIC_LRC_SUPPORT) {
Log.v(TAG, "reload Lyrics @startPlayback()");
reloadLyrics();
updateLyricsFrame();
updateLyrics();
}
// mtk80658
long next = refreshNow();
queueNextRefresh(next);
}
private ServiceConnection osc = new ServiceConnection() {
public void onServiceConnected(ComponentName classname, IBinder obj) {
mService = IMediaPlaybackService.Stub.asInterface(obj);
startPlayback();
try {
// Assume something is playing when the service says it is,
// but also if the audio ID is valid but the service is paused.
if (mService.getAudioId() >= 0 || mService.isPlaying() ||
mService.getPath() != null) {
// something is playing now, we're done
mRepeatButton.setVisibility(View.VISIBLE);
mShuffleButton.setVisibility(View.VISIBLE);
mQueueButton.setVisibility(View.GONE);
setRepeatButtonImage();
setShuffleButtonImage();
setPauseButtonImage();
return;
}
} catch (RemoteException ex) {
}
// Service is dead or not playing anything. If we got here as part
// of a "play this file" Intent, exit. Otherwise go to the Music
// app start screen.
if (getIntent().getData() == null) {
Intent intent = new Intent(Intent.ACTION_MAIN);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intent.setClass(MediaPlaybackActivity.this, MusicBrowserActivity.class);
startActivity(intent);
}
finish();
}
public void onServiceDisconnected(ComponentName classname) {
mService = null;
}
};
private void setRepeatButtonImage() {
if (mService == null) return;
try {
switch (mService.getRepeatMode()) {
case MediaPlaybackService.REPEAT_ALL:
mRepeatButton.setImageResource(R.drawable.ic_mp_repeat_all_btn);
break;
case MediaPlaybackService.REPEAT_CURRENT:
mRepeatButton.setImageResource(R.drawable.ic_mp_repeat_once_btn);
break;
default:
mRepeatButton.setImageResource(R.drawable.ic_mp_repeat_off_btn);
break;
}
} catch (RemoteException ex) {
}
}
private void setShuffleButtonImage() {
if (mService == null) return;
try {
switch (mService.getShuffleMode()) {
case MediaPlaybackService.SHUFFLE_NONE:
mShuffleButton.setImageResource(R.drawable.ic_mp_shuffle_off_btn);
break;
case MediaPlaybackService.SHUFFLE_AUTO:
mShuffleButton.setImageResource(R.drawable.ic_mp_partyshuffle_on_btn);
break;
default:
mShuffleButton.setImageResource(R.drawable.ic_mp_shuffle_on_btn);
break;
}
} catch (RemoteException ex) {
}
}
private void setPauseButtonImage() {
try {
if (mService != null && mService.isPlaying()) {
// mPauseButton.setImageResource(android.R.drawable.ic_media_pause);
mPauseButton.setImageResource(R.drawable.stat_music_stop_1);
mPosOverride = -1;
} else {
// mPauseButton.setImageResource(android.R.drawable.ic_media_play);
mPauseButton.setImageResource(R.drawable.stat_music_play_1);
}
} catch (RemoteException ex) {
}
}
private ImageView mAlbum;
private TextView mCurrentTime;
private TextView mTotalTime;
private TextView mArtistName;
private TextView mAlbumName;
private TextView mTrackName;
private ProgressBar mProgress;
private long mPosOverride = -1;
private boolean mFromTouch = false;
private long mDuration;
private int seekmethod;
private boolean paused;
private static final int REFRESH = 1;
private static final int QUIT = 2;
private static final int GET_ALBUM_ART = 3;
private static final int ALBUM_ART_DECODED = 4;
// mtk80658: add for Music lyrics supporting
private static final int UPDATE_LRC = 5;
// mtk80658
private void queueNextRefresh(long delay) {
if (!paused) {
Message msg = mHandler.obtainMessage(REFRESH);
mHandler.removeMessages(REFRESH);
mHandler.sendMessageDelayed(msg, delay);
}
}
private long refreshNow() {
if(mService == null)
return 500;
try {
long pos = mPosOverride < 0 ? mService.position() : mPosOverride;
if (pos + 100 > mDuration) {
Log.d(TAG, "refreshNow, do a workaround for position");
pos = mDuration;
}
long remaining = 1000 - (pos % 1000);
if ((pos >= 0) && (mDuration > 0)) {
mCurrentTime.setText(MusicUtils.makeTimeString(this, pos / 1000));
if (mService.isPlaying()) {
mCurrentTime.setVisibility(View.VISIBLE);
} else {
// blink the counter
int vis = mCurrentTime.getVisibility();
mCurrentTime.setVisibility(vis == View.INVISIBLE ? View.VISIBLE : View.INVISIBLE);
remaining = 500;
}
if (!mFromTouch)
mProgress.setProgress((int) (1000 * pos / mDuration));
// mtk80658: add for Music lyrics supporting
if (FeatureOption.MTK_MUSIC_LRC_SUPPORT) {
// scroll lyric (multiple line lyrics) or move up one next line (single line) here
if (mLrcReady) {
if (mScrollLrcReady) { // if the scroll view is already, then just scroll it
mScrollLrcView.scrollLyrics(this, (int)pos);
}
else { // if the scroll view is not ready, then need to update the lyric display
Log.v(TAG, "Lyrics is not ready, send message to update it");
mHandler.sendEmptyMessage(UPDATE_LRC);
}
}
}
// mtk80658
} else {
mCurrentTime.setVisibility(View.VISIBLE);
mCurrentTime.setText("0:00");
mTotalTime.setText("--:--");
if (!mFromTouch)
mProgress.setProgress(0);
}
// Correct duration for MP3/AMR/AWB/AAC formats
if (mNeedUpdateDuration && mService.isPlaying()) {
long newDuration = mService.duration();
if (newDuration > 0L && newDuration != mDuration) {
mDuration = newDuration;
mNeedUpdateDuration = false;
// Update UI
mTotalTime.setText(MusicUtils.makeTimeString(this, mDuration / 1000));
Log.i(TAG, "new duration updated!!");
String id = null;
try {
id = String.valueOf(mService.getAudioId());
} catch (RemoteException e) {
}
}
} else if (pos < 0 || pos >= mDuration) {
mNeedUpdateDuration = false;
}
// return the number of milliseconds until the next full second, so
// the counter can be updated at just the right time
return remaining;
} catch (RemoteException ex) {
}
return 500;
}
private final Handler mHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case ALBUM_ART_DECODED:
mAlbum.setImageBitmap((Bitmap)msg.obj);
mAlbum.getDrawable().setDither(true);
break;
case REFRESH:
long next = refreshNow();
queueNextRefresh(next);
break;
case QUIT:
// This can be moved back to onCreate once the bug that prevents
// Dialogs from being started from onCreate/onResume is fixed.
new AlertDialog.Builder(MediaPlaybackActivity.this)
.setTitle(R.string.service_start_error_title)
.setMessage(R.string.service_start_error_msg)
.setPositiveButton(R.string.service_start_error_button,
new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int whichButton) {
finish();
}
})
.setCancelable(false)
.show();
break;
// mtk80658: add for Music lyrics supporting
case UPDATE_LRC:
if (FeatureOption.MTK_MUSIC_LRC_SUPPORT) {
if (null != mScrollLrcView) {
mScrollLrcView.update();
mScrollLrcReady = true;
}
refreshNow();
}
break;
// mtk80658
default:
break;
}
}
};
private BroadcastReceiver mStatusListener = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
Log.d(TAG, "mStatusListener: " + action);
if (action.equals(MediaPlaybackService.META_CHANGED)) {
// redraw the artist/title info and
// set new max for progress bar
updateTrackInfo();
setPauseButtonImage();
// mtk80658: add for Music lyrics supporting
if (FeatureOption.MTK_MUSIC_LRC_SUPPORT) {
mHandler.removeMessages(REFRESH); // add by Yiqi Kang 20110516 evening
Log.v(TAG, "reload Lyrics @META_CHANGED message");
reloadLyrics();
updateLyricsFrame();
updateLyrics();
}
// mtk80658
queueNextRefresh(1);
} else if (action.equals(MediaPlaybackService.PLAYSTATE_CHANGED)) {
setPauseButtonImage();
} else if (action.equals(MediaPlaybackService.QUIT_PLAYBACK)) {
mHandler.removeMessages(REFRESH);
finish();
} else if (action.equals(Intent.ACTION_SCREEN_OFF)) {
// stop refreshing
Log.d(TAG, "onReceive, stop refreshing ...");
mHandler.removeMessages(REFRESH);
} else if (action.equals(Intent.ACTION_SCREEN_ON)) {
// restore refreshing
Log.d(TAG, "onReceive, restore refreshing ...");
long next = refreshNow();
queueNextRefresh(next);
}
}
};
private BroadcastReceiver mUnmountReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (Intent.ACTION_MEDIA_EJECT.equals(action)) {
Log.i(TAG, "unmount receiver: MEDIA_EJECT, finish self!!");
finish();
}
}
};
private static class AlbumSongIdWrapper {
public long albumid;
public long songid;
AlbumSongIdWrapper(long aid, long sid) {
albumid = aid;
songid = sid;
}
}
private void updateTrackInfo() {
if (mService == null) {
return;
}
try {
String path = mService.getPath();
if (path == null) {
finish();
return;
}
long songid = mService.getAudioId();
if (songid < 0 && path.toLowerCase().startsWith("http://")) {
// Once we can get album art and meta data from MediaPlayer, we
// can show that info again when streaming.
((View) mArtistName.getParent()).setVisibility(View.INVISIBLE);
((View) mAlbumName.getParent()).setVisibility(View.INVISIBLE);
mAlbum.setVisibility(View.GONE);
mTrackName.setText(path);
mAlbumArtHandler.removeMessages(GET_ALBUM_ART);
mAlbumArtHandler.obtainMessage(GET_ALBUM_ART, new AlbumSongIdWrapper(-1, -1)).sendToTarget();
} else {
((View) mArtistName.getParent()).setVisibility(View.VISIBLE);
((View) mAlbumName.getParent()).setVisibility(View.VISIBLE);
String artistName = mService.getArtistName();
if (MediaStore.UNKNOWN_STRING.equals(artistName)) {
artistName = getString(R.string.unknown_artist_name);
}
mArtistName.setText(artistName);
String albumName = mService.getAlbumName();
long albumid = mService.getAlbumId();
if (MediaStore.UNKNOWN_STRING.equals(albumName)) {
albumName = getString(R.string.unknown_album_name);
albumid = -1;
}
mAlbumName.setText(albumName);
mTrackName.setText(mService.getTrackName());
mAlbumArtHandler.removeMessages(GET_ALBUM_ART);
mAlbumArtHandler.obtainMessage(GET_ALBUM_ART, new AlbumSongIdWrapper(albumid, songid)).sendToTarget();
mAlbum.setVisibility(View.VISIBLE);
}
mDuration = mService.duration();
mTotalTime.setText(MusicUtils.makeTimeString(this, mDuration / 1000));
// For mp3/aac/amr/awb file, its duration need to be updated when playing
String mimeType = mService.getMIMEType();
if (mimeType != null) {
Log.i(TAG, "mimeType=" + mimeType);
}
if (mimeType != null && (mimeType.equals("audio/mpeg")
|| mimeType.equals("audio/amr")
|| mimeType.equals("audio/amr-wb")
|| mimeType.equals("audio/aac"))) {
mNeedUpdateDuration = true;
} else {
mNeedUpdateDuration = false;
}
} catch (RemoteException ex) {
finish();
}
}
// mtk80658: add for Music lyrics supporting
private void reloadLyrics() {
if (FeatureOption.MTK_MUSIC_LRC_SUPPORT) {
if (mService == null) {
return;
}
mLrcReady = false;
mScrollLrcReady = false;
// get sound track file name from service
String filePathName = null;
try {
filePathName = mService.getTrackFilePathName();
if (filePathName == null) {
finish();
return;
}
} catch (RemoteException ex) {
finish();
}
// now load lyrics here, or should launch another thread if performance matters.
if (!mLrcReady) {
mLrcReady = mScrollLrcView.loadLyrics(this, filePathName);
}
} // if (FeatureOption.MTK_MUSIC_LRC_SUPPORT)
}
// mtk80658
// mtk80658: add for Music lyrics supporting
private void updateLyrics() {
if (FeatureOption.MTK_MUSIC_LRC_SUPPORT) {
if (mService == null) {
return;
}
// get sound track file name from service
String filePathName = null;
try {
filePathName = mService.getTrackFilePathName();
if (filePathName == null) {
finish();
return;
}
} catch (RemoteException ex) {
finish();
}
try {
if (!mScrollLrcReady) {
mScrollLrcView.setupLyrics(this, filePathName, mLrcMode, (int)mService.position());
}
} catch (RemoteException ex) {
throw new LrcScrollException();
}
}
}
// mtk80658
// mtk80658: add for Music lyrics supporting
private void updateLyricsFrame() {
if (FeatureOption.MTK_MUSIC_LRC_SUPPORT) {
if (mService == null) {
return;
}
FrameLayout fl = (FrameLayout) findViewById(R.id.lyrics_frame);
LayoutParams lp = fl.getLayoutParams();
LinearLayout ll = (LinearLayout) findViewById(R.id.lyrics_layout);
ImageView iv = (ImageView) findViewById(R.id.lyrics_shift);
switch (mLrcMode) {
case ScrollLrcView.LRC_MODE_SINGLE:
lp.height = mScrollLrcView.singleLineModeHeightPixel();
ll.setPadding(0, 0, 0, 0);
iv.setBackgroundResource(R.drawable.lyrics_switch_single_mode);
break;
case ScrollLrcView.LRC_MODE_MULTIPLE:
lp.height = LayoutParams.MATCH_PARENT;
ll.setPadding(0, mScrollLrcView.singleLineModePaddingPixel(),
0, mScrollLrcView.singleLineModePaddingPixel());
iv.setBackgroundResource(R.drawable.lyrics_switch_multiple_mode);
break;
default:
break;
}
fl.setLayoutParams(lp);
}
}
// mtk80658
public class AlbumArtHandler extends Handler {
private long mAlbumId = -1;
public AlbumArtHandler(Looper looper) {
super(looper);
}
@Override
public void handleMessage(Message msg)
{
long albumid = ((AlbumSongIdWrapper) msg.obj).albumid;
long songid = ((AlbumSongIdWrapper) msg.obj).songid;
if (msg.what == GET_ALBUM_ART && (mAlbumId != albumid || albumid < 0)) {
// while decoding the new image, show the default album art
Message numsg = mHandler.obtainMessage(ALBUM_ART_DECODED, null);
mHandler.removeMessages(ALBUM_ART_DECODED);
mHandler.sendMessageDelayed(numsg, 300);
Bitmap bm = MusicUtils.getArtwork(MediaPlaybackActivity.this, songid, albumid);
if (bm == null) {
bm = MusicUtils.getArtwork(MediaPlaybackActivity.this, songid, -1);
albumid = -1;
}
if (bm != null) {
numsg = mHandler.obtainMessage(ALBUM_ART_DECODED, bm);
mHandler.removeMessages(ALBUM_ART_DECODED);
mHandler.sendMessage(numsg);
}
mAlbumId = albumid;
}
}
}
private static class Worker implements Runnable {
private final Object mLock = new Object();
private Looper mLooper;
/**
* Creates a worker thread with the given name. The thread
* then runs a {@link android.os.Looper}.
* @param name A name for the new thread
*/
Worker(String name) {
Thread t = new Thread(null, this, name);
t.setPriority(Thread.MIN_PRIORITY);
t.start();
synchronized (mLock) {
while (mLooper == null) {
try {
mLock.wait();
} catch (InterruptedException ex) {
}
}
}
}
public Looper getLooper() {
return mLooper;
}
public void run() {
synchronized (mLock) {
Looper.prepare();
mLooper = Looper.myLooper();
mLock.notifyAll();
}
Looper.loop();
}
public void quit() {
mLooper.quit();
}
}
}